#include "commData.h"
#include "protocol.h"
#include "CRC_Generate.h"
#include "protocol_bms.h"

FunType_bufferTx   bms_lowTx;
/*
note: this part is reference from modbus
sci communication parameter:
speed:9600
checksum:even
stopbit:1
slave add:0x01
*/
bms_resultInfo	bms_result;
bms_tinfo 		bms_proinfo;

//#define 	bms_ID			(1)
//#define   	bms_group		(5)
//#define 	bms_head		(0xDD)
//#define 	bms_tail		(0x77)
list_prot 	bms_queue_tx;
mesg_prot		bms_info[1];
uint8_t   	u8_bms_acknum = 0;

void queue_insert_bms(pmesg_prot pmesg)
{
	uint8_t pos, status, len, i;
	plist_prot pqueue;
	pqueue = &bms_queue_tx;
	pos = pqueue->head;
	if(mesg_max==pos)pos = 0;
	status = pmesg->status;
	if(0==status){
		len = pmesg->len;		
		pqueue->mesg_queue[pos].status = status;
		pqueue->mesg_queue[pos].ID = pmesg->ID;
		pqueue->mesg_queue[pos].len = len;
		for(i=0; i<(len); i++){
			pqueue->mesg_queue[pos].buffer[i] = pmesg->buffer[i];
		}
		pqueue->head++;
		if(mesg_max==pqueue->head)pqueue->head=0;
		if(pqueue->size<10)pqueue->size++;		
	}
}

static void bms_basicinfo_Read(pmesg_prot mesg)
{
	uint8_t offset;
	//buffer index from (3~len+3) is the register result
	offset = 3;
	//volt
	bms_result.volt = mesg->buffer[offset++];
	bms_result.volt = (bms_result.volt<<8)+mesg->buffer[offset++];
	//current
	bms_result.current = mesg->buffer[offset++];
	bms_result.current = (bms_result.current<<8)+mesg->buffer[offset++];
	//capacity
	bms_result.capacity = mesg->buffer[offset++];
	bms_result.capacity = (bms_result.capacity<<8)+mesg->buffer[offset++];
	//cab_capacity
	bms_result.cab_capacity = mesg->buffer[offset++];
	bms_result.cab_capacity = (bms_result.cab_capacity<<8)+mesg->buffer[offset++];
	//loop_count
	bms_result.loop_count = mesg->buffer[offset++];
	bms_result.loop_count = (bms_result.loop_count<<8)+mesg->buffer[offset++];
	//date
	bms_result.date = mesg->buffer[offset++];
	bms_result.date = (bms_result.date<<8)+mesg->buffer[offset++];
	//equal_states
	bms_result.equal_states = mesg->buffer[offset++];
	bms_result.equal_states = (bms_result.equal_states<<8)+mesg->buffer[offset++];
	//equal_states_high
	bms_result.equal_states_high = mesg->buffer[offset++];
	bms_result.equal_states_high = (bms_result.equal_states_high<<8)+mesg->buffer[offset++];
	//protect_states
	bms_result.protect_states = mesg->buffer[offset++];
	bms_result.protect_states = (bms_result.protect_states<<8)+mesg->buffer[offset++];
	//soft_version
	bms_result.soft_version = mesg->buffer[offset++];
	bms_result.soft_version = (bms_result.soft_version<<8)+mesg->buffer[offset++];
	//RSOC
	bms_result.RSOC = mesg->buffer[offset++];
	bms_result.RSOC = (bms_result.RSOC<<8)+mesg->buffer[offset++];
	//FET_cont_states
	bms_result.FET_cont_states = mesg->buffer[offset++];
	bms_result.FET_cont_states = (bms_result.FET_cont_states<<8)+mesg->buffer[offset++];
	//batt_seri_count
	bms_result.batt_seri_count = mesg->buffer[offset++];
	bms_result.batt_seri_count = (bms_result.batt_seri_count<<8)+mesg->buffer[offset++];
	//ntc_count
	bms_result.ntc_count = mesg->buffer[offset++];
	bms_result.ntc_count = (bms_result.ntc_count<<8)+mesg->buffer[offset++];
	//ntc_1
	bms_result.ntc_1 = mesg->buffer[offset++];
	bms_result.ntc_1 = (bms_result.ntc_1<<8)+mesg->buffer[offset++];
	//ntc_2
	bms_result.ntc_2 = mesg->buffer[offset++];
	bms_result.ntc_2 = (bms_result.ntc_2<<8)+mesg->buffer[offset++];
}

static void bms_singlevolt_Read(pmesg_prot mesg)
{
	uint8_t offset, i;
	//buffer index from (3~len+3) is the register result
	offset = 3;
	//seri1_volt
	for(i=0; i<7;i++){
		bms_result.seri_volt[i] = mesg->buffer[offset++];
		bms_result.seri_volt[i] = (bms_result.seri_volt[i]<<8)+mesg->buffer[offset++];
	}
}

static void bms_hardwareVersion_Read(pmesg_prot mesg)
{
	uint8_t offset, i;
	//buffer index from (3~len+3) is the register result
	offset = 3;
	//seri1_volt
	for(i=0; i<8;i++){
		bms_result.version[i] = mesg->buffer[offset++];
	}
}

static uint8_t bms_process(pmesg_prot mesg)
{
	uint8_t offset;
	//buffer index from (2~len+2) is the register result
	offset = 1;
	//status check
	u8_bms_status = mesg->buffer[offset++];
	if(0!=u8_bms_status){
		return 1;
	}
	//cmds check
	switch(mesg->ID){
		case(0x03):
			//basic info get
			bms_basicinfo_Read(mesg);
		break;
		case(0x04):
			//read single volt
			bms_singlevolt_Read(mesg);
		break;
		case(0x05):
			//hardware version get
			bms_hardwareVersion_Read(mesg);
		break;		
		default:
		break;
	}
	//result process	
	u8_bms_acknum = 0;
	return 0;
}

static uint8_t bms_rxFunc(void)
{
	return 0;	
}

static uint8_t bms_frametx(pmesg_prot mesg)
{
	uint8_t i, index;
	uint16_t crc = 0;
	uint8_t buffer[128];
	index = 0;
	//mesg_head insert
	buffer[index++] = 0xDD;
	//buffer insert
	for(i=0; i<mesg->len; i++){
		buffer[index++] = mesg->buffer[i];
	}
	//CRC_Generate
	crc = bms_GetCrC(buffer, index);
	buffer[index++] = (uint8_t)(crc>>8);
	buffer[index++] = (uint8_t)(crc>>0);
	//mesg_tail insert
	buffer[index++] = 0x77;
	//tx frame
	bms_lowTx(buffer, index);
	bms_proinfo.lastCmd = mesg->ID;
	u8_bms_acknum++;
	return 0;
}
static uint8_t bms_txFunc(void)
{
	uint8_t result;
	uint8_t pos;
	plist_prot pqueue;
	//second, rx data pro
	pqueue = &bms_queue_tx;
	//size = pqueue->size;
	//while(pqueue->size>0){
	if(pqueue->size>0){
		pos = pqueue->tail;
		if(pos>=mesg_max)pos=0;
		//result pro
		result = bms_frametx(&(pqueue->mesg_queue[pos]));
		pqueue->tail++;
		if(pqueue->tail>=mesg_max)pqueue->tail=0;		
		pqueue->size--;
	}
	return result;
}

uint8_t bms_period_callback(void)
{	
	if(bms_proinfo.timer<4){
		bms_proinfo.timer++;
	}else{
		bms_proinfo.timer = 4;
		bms_proinfo.step = 0;
		bms_proinfo.count = 0;
		bms_proinfo.crc16 = 0;
		bms_proinfo.crc16_T = 0;
		bms_proinfo.len = 0;
	}
	return 0;
}

void bms_rxFunc_callback(uint8_t data_rx)
{
	bms_Pinfo PproT;
	PproT = &bms_proinfo;
	//first, start flag check
	if(PproT->timer>3){		
		bms_info[0].status=1;
		PproT->count = 0;
		if(bms_head==data_rx){
			PproT->step = 1;
			return;
		}				
	}else{
		if(0==PproT->step){
			if(bms_head==data_rx){
				PproT->step = 1;
				PproT->count = 0;
				bms_info[0].status=1;
				return;
			}
		}
	}
	PproT->timer = 0;
	switch(PproT->step){
		case(1):
			//second, cmd check
			bms_info[0].buffer[PproT->count++] = data_rx;
			if(2==PproT->count){
				PproT->step = 2;
			}
		break;
		case(2):
			//third, len check
			bms_info[0].buffer[PproT->count++] = data_rx;
			PproT->len = data_rx;
			bms_info[0].len = data_rx + 3;//add the cmd , result, len 
			PproT->step = 3;
		break;
		case(3):
			//four, data buffer
			if(PproT->count<(PproT->len+3)){
				bms_info[0].buffer[PproT->count++] = data_rx;
			}else{
				//five, checksum
				PproT->crc16 = bms_GetCrC(bms_info[0].buffer, PproT->count);
				bms_info[0].buffer[PproT->count++] = data_rx;
				PproT->crc16_T = data_rx;
				PproT->step = 4;
			}
		break;
		case(4):
			//six, end check
			PproT->crc16_T = (PproT->crc16_T<<8) + data_rx;
			bms_info[0].buffer[PproT->count++] = data_rx;
			if(PproT->crc16 == PproT->crc16_T)
			{
				bms_info[0].status=0;
				bms_info[0].ID = PproT->lastCmd;
				//insert data
				list_insert(&bms_info[0],bms_group);
			}
			//reset
			PproT->step = 0;
			PproT->count = 0;
		break;
		default:
			PproT->step = 0;
			PproT->count = 0;
		break;
	}
}

/*
Cmds
*/

/*
status check:DD A5 03 00 FF FD 77
*/
uint8_t bms_basicstatus_Get(void)
{
	uint8_t count;
	mesg_prot Tmesg;
	Tmesg.status = 0;
	Tmesg.ID = 0x03;
	count = 0;
	Tmesg.buffer[count++] = 0xA5;
	Tmesg.buffer[count++] = 0x03;
	Tmesg.buffer[count++] = 0x00;
	//Tmesg.buffer[count++] = 0xFF;
	//Tmesg.buffer[count++] = 0xFD;
	Tmesg.len = count;
	queue_insert_bms(&Tmesg);
	u8_bms_acknum++;
	return 0;
}
/*
Read single volt 
:DD A5 04 00 FF FC 77
*/
uint8_t bms_singlevolt_Get(void)
{
	uint8_t count;
	mesg_prot Tmesg;
	Tmesg.status = 0;
	Tmesg.ID = 0x04;
	count = 0;
	Tmesg.buffer[count++] = 0xA5;
	Tmesg.buffer[count++] = 0x04;
	Tmesg.buffer[count++] = 0x00;
	//Tmesg.buffer[count++] = 0xFF;
	//Tmesg.buffer[count++] = 0xFC;
	Tmesg.len = count;
	queue_insert_bms(&Tmesg);
	return 0;
}

/*
Get hardware version 
:DD A5 05 00 FF FB 77
*/
uint8_t bms_hardwareVersion_Get(void)
{
	uint8_t count;
	mesg_prot Tmesg;
	Tmesg.status = 0;
	Tmesg.ID = 0x05;
	count = 0;
	Tmesg.buffer[count++] = 0xA5;
	Tmesg.buffer[count++] = 0x05;
	Tmesg.buffer[count++] = 0x00;
	//Tmesg.buffer[count++] = 0xFF;
	//Tmesg.buffer[count++] = 0xFB;
	Tmesg.len = count;
	queue_insert_bms(&Tmesg);
	return 0;
}

static uint8_t bms_lowtx(uint8_t *buffer, uint8_t len)
{
  return 0;  
}
/*
user can use this function to change low tx function
*/
void bms_lowTxfunc_Register(FunType_bufferTx txFunc)
{
	bms_lowTx = txFunc;
}

void bms_init(FunType_bufferTx txFunc)
{
	//register function
	func_register_init(bms_group, bms_rxFunc, bms_txFunc, bms_process);
	bms_lowTx = txFunc;
}

/*
this function should be call by application periodly
*/
uint8_t bms_task(void)
{
	uint8_t result = 0;
	//get the status of upmotor
	//bms_basicstatus_Get();
	//get the single volt 
	//bms_singlevolt_Get();
	result = list_check(bms_group);
	return result;
}

uint8_t bms_interfaceTest(void)
{
	uint8_t result = 0;
	//get the status of upmotor
	bms_basicstatus_Get();
	//get the single volt 
	bms_singlevolt_Get();
	//result = list_check(bms_group);
	return result;
}


